#define push_rbp  0x55
#define rsp2rbp   X64_PRE, 0x89, 0xE5

// word: 字节数， level: 0
// #define enter2(word) 0xC8, (word * sizeof(PN)) & 0xFF, (word * sizeof(PN)) >> 8, 0
#define enter2(word) 0xC8, (word) & 0xFF, ((word) >> 8) && 0xFF, 0

// sub rsp, %rsp
#define alloc_locals1(byte) X64_PRE, 0x83, 0xEC, byte
#define alloc_locals4(dword) X64_PRE, 0x81, 0xEC, UNPACK4(dword)

#define leave_ret 0xC9, 0xC3
#if __WORDSIZE == 64
  #define ret           0xC3
// #else
  // #define ret     0x5D, 0xC3
#endif

#define set_rax(x)  X64_PRE, 0xB8, UNPACK8(x)
#define set_eax(x)           0xB8, UNPACK4(x)
// callq %rax
#define call_rax             0xFF, 0xD0

// 把 4 字节 x 写入 reg[0,~] 号变量
// TODO hsq 内嵌汇编 movl $1, -8(%%rsp) 得到    C7 44 24 F8 01 00 00 00
//                  movq $1, -8(%%rsp) 得到 48 C7 44 24 F8 01 00 00 00
#define dword2reg(reg, x) \
  X64_PRE, 0xC7,    /* movl */ \
  0x45, RBP(reg),   /* -A(%rbp) */ \
  UNPACK4((PN)(x))

#define DWORD2REG(reg, x) ASM_BYTES(dword2reg(reg, x))

#define rax2rdx     X64_PRE, 0x89, 0xC2
// x[0,~] 号变量 -> %rax
#define reg2rax(n)  X64_PRE, 0x8B, 0x45, RBP(n)
// %rax -> x[0,~] 号变量
#define rax2reg(n)  X64_PRE, 0x89, 0x45, RBP(n)

// x[0,~] 号变量 -> %rdx
#define reg2rdx(n)  X64_PRE, 0x8B, 0x55, RBP(n)
// %rdx -> x[0,~] 号变量
#define rdx2reg(n)  X64_PRE, 0x89, 0x55, RBP(n)

#define test_al(byte) 0xF6, 0xC0, (byte)
#define test_dl(byte) 0xF6, 0xC2, (byte)
// test dword, %eax
#define test_eax_(dword) 0xF7, 0xC0, UNPACK4(dword)
// test %rax, %rax
#define test_rax X64_PRE, 0x85, 0xC0
// test %eax, %eax
#define test_eax 0x85, 0xC0
// cmpq dword, (%eax)
#define cmpq_mem_in_eax(dword) 0x81, 0x38, UNPACK4(dword)
// cmp dword, %edi
#define cmp_edi_(dword) 0x81, 0xFF, UNPACK4(dword)
// cmp %eax, %edx
#define cmp_eax2edx 0x39, 0xC2
// cmp PN_FALSE, %rax
#define rax_is_false X64_PRE, 0x83, 0xF8, PN_FALSE

// mov offset(%rax), %rax
#define unbox_rax(typ, field)   X64_PRE, 0x8B, 0x40, offsetof(struct typ, field)
// mov (%rax), %rax
#define unbox_rax0              X64_PRE, 0x8B, 0
// mov %rdx, N(%rax)
// TODO hsq 3 处调用中的 2 处是 PNWeakRef.data
#define box_rdx1(byte)          X64_PRE, 0x89, 0x50, (byte)

// lea
#define OP_box_num 0x8D
// lea 0x1(%eax,%eax,1),%eax
#define box_num_in_eax OP_box_num, 0x44, 0x00, 0x01
// lea 0x1(%rax,%rax,1),%rax
#define box_num_in_rax X64_PRE, OP_box_num, 0x44, 0x00, 0x01
// lea 0x1(%edx,%edx,1),%eax
#define box_num_in_edx_to_eax OP_box_num, 0x44, 0x12, 0x01
// X64_PRE, 0x8D, 0x44, 0x10, 0xFF // lea -1(%rax,%rdx,1),%rax
// X64_PRE, 0x8D, 0x4C, 0x09, 0xFF, // leaq    -1(%rcx,%rcx),  %rcx
// sar %eax
#define unbox_num_in_eax  0xD1, 0xF8
// sar %edx
#define unbox_num_in_edx  0xD1, 0xFA


#define JMP4(dword) ASM_BYTES(0xE9, UNPACK4(dword))
// jmp short N
#define jmp1(byte) 0xEB, (byte)

#define OP_je1  0x74
#define OP_jne1 0x75
#define OP_jl1  0x7C
#define OP_jge1 0x7D
#define OP_jle1 0x7E
#define OP_jg1  0x7F
// je == jz
#define je1(byte)   OP_je1, (byte)
#define jne1(byte)  OP_jne1, (byte)

// add dword, %rax
#define add_rax_(dword) X64_PRE, 0x05, UNPACK4(dword)


// 计算 __VA_ARGS__ 参数个数,最大支持64个参数
#define FL_ARG_COUNT(...) FL_INTERNAL_ARG_COUNT_PRIVATE(0, ##__VA_ARGS__,\
  64, 63, 62, 61, 60, \
  59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
  49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
  39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
  29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
  19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
  9,  8,  7,  6,  5,  4,  3,  2,  1,  0)
#define FL_INTERNAL_ARG_COUNT_PRIVATE(\
   _0,  _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,  _9, \
  _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \
  _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \
  _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \
  _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, \
  _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, \
  _60, _61, _62, _63, _64, N, ...) N
